import { _decorator, Component, EventTouch, instantiate, Label, Node, Prefab, Size, size, UITransform, v2, v3, Vec2, Vec3 } from 'cc';
import EventManager from '../../Init/Managers/EventManager';
import { EventTypes } from '../../Init/Managers/EventTypes';
import { StorageSystem } from '../../Init/SystemStorage/StorageSystem';
const { ccclass, property } = _decorator;
const tmpV = v3();
const tmpV2 = v2();
const tmpP = v3();
const tmpP1 = v3();
const tmpP2 = v3();

@ccclass('gridLayer')
export class gridLayer extends Component {

    @property(Node)
    gridNode: Node = null;
    @property(Node)
    board: Node = null;
    @property(Node)
    ball: Node = null;
    @property(Node)
    touchPanel: Node = null;
    @property(Node)
    role: Node = null;
    @property(Node)
    btmLine: Node = null;
    @property(Node)
    effectLayer: Node = null;
    @property(Node)
    tip: Node = null;
    @property(Node)
    bubble: Node = null;

    boardSize = size();
    gridSize = size();
    ballSize = size();
    roleSize = size();
    btmLineY = 0;
    isStart = false;

    protected onLoad(): void {
        this.boardSize.set(this.board.getComponent(UITransform).contentSize);
        this.gridSize.set(this.gridNode.getComponent(UITransform).contentSize);
        this.ballSize.set(this.ball.getComponent(UITransform).contentSize);
        this.roleSize.set(this.role.getComponent(UITransform).contentSize);
        this.btmLineY = this.btmLine.position.y;
    }

    protected onEnable(): void {
        this.initGrids();
        this.initRole();
        this.initTouch();
        this.initBall();
        this.initEffect();
        this.initScore();
    }
    protected onDisable(): void {
        this.resetGrids();
        this.resetRole();
        this.resetTouch();
        this.resetBall();
        this.resetEffect();
        this.resetScore();
    }

    protected update(dt: number): void {
        if (!this.isStart) return;
        this.updateGrids(dt);
        this.updateRole(dt);
        this.updateBall(dt);
        this.updateEffect(dt);
    }

    protected onGameOver(isWin: boolean) {
        this.isStart = false;
        //
        EventManager.emit(EventTypes.GameEvents.GameOver, isWin);
    }

    //#region ---砖块
    hitCount = 0;
    moveSpd = -20;
    moveDist = 0;
    grids: { node: Node, pos: Vec3 }[] = [];
    // 间隔
    gridSpace = 80;
    // 水平摆放最大数量
    maxXCount = 5;
    initPos = v3(-202, 736);
    crateRate = 0.5;

    initGrids() {
        //
        let curLv = StorageSystem.getData().levelAssets.curLv;
        this.moveSpd = -(20 + (curLv - 1) * 2);
        this.moveSpd = Math.max(this.ballSpd, -100);
        this.crateRate = Math.min(0.5 + (curLv - 1) * 0.03, 0.9);


        this.node.removeAllChildren();
        // 计算水平最大数量
        this.maxXCount = Math.floor(this.boardSize.width / this.gridSize.width);

        // 初始生成位置--顶部边界+3排,总共生成5排
        let pos = v3();
        for (let j = 0; j < 6; j++) {
            pos.y = this.initPos.y - this.gridSpace * j;
            for (let i = 0; i < this.maxXCount; i++) {
                pos.x = this.initPos.x + this.gridSpace * i;

                if (Math.random() < this.crateRate) {
                    this.createGrids(pos);
                }
            }
        }
    }

    resetGrids() {
        this.grids.length = 0;
        this.hitCount = 0;
        this.moveDist = 0;
    }
    createGrids(pos: Vec3) {
        let node = instantiate(this.gridNode);
        node.parent = this.node;
        node.setPosition(pos);
        this.grids.push({ node: node, pos: v3(pos) });
        // 随机一种颜色
        let idx = Math.floor(Math.random() * node.children.length);
        for (let i = 0; i < node.children.length; i++) {
            node.children[i].active = i == idx;
        }
    }

    updateGrids(dt) {
        let step = this.moveSpd * dt;
        // 间隔创建
        this.moveDist += step;
        if (Math.abs(this.moveDist) >= this.gridSpace) {
            this.moveDist = 0;
            //随机位置创建一排
            tmpP.set(this.initPos);
            for (let i = 0; i < this.maxXCount; i++) {
                tmpP.x = this.initPos.x + this.gridSpace * i;
                if (Math.random() < this.crateRate) {
                    this.createGrids(tmpP);
                }
            }
        }
        // 移动grid 判断是否越界
        for (let idx = 0; idx < this.grids.length; idx++) {
            const g = this.grids[idx];
            if (g.pos.y < this.btmLineY + this.gridSize.height * 0.5) {
                this.onGameOver(false);
                break;
            }
            g.pos.y += step;
            g.node.setPosition(g.pos);
        }
    }
    checkGrids(p: Vec3, r: number): boolean {
        // 最大碰撞距离
        let minW = this.gridSize.width * 0.5 + r;

        for (let idx = 0; idx < this.grids.length; idx++) {
            const g = this.grids[idx];
            tmpP.set(p).subtract(g.pos);
            // 计算AABB碰撞
            if (Math.abs(tmpP.x) <= minW && Math.abs(tmpP.y) <= minW) {

                this.removeGrid(idx);
                return true;
            }
        }
        return false;
    }

    // 移除grid
    removeGrid(idx: number) {
        let grid = this.grids.splice(idx, 1)[0];
        this.showEffect(grid.node.position);
        grid.node.removeFromParent();
        grid.node.destroy();
        this.hitCount++;

        this.addScore(1);
    }

    //#endregion

    //#region ---角色
    rolePos = v3();
    initRolePos = v3(0, -265, 0);
    // 玩家移动方向
    roleVec = v3();

    initRole() {
        this.rolePos.set(this.initRolePos);
        this.role.setPosition(this.rolePos);
        this.roleVec.set(0, 0, 0);
    }
    resetRole() {

    }
    updateRole(dt) {
        let subX = this.touchX - this.rolePos.x;
        this.rolePos.x += subX * 0.5;
        // 判断移动方向
        if (Math.abs(subX) > 1) {
            this.roleVec.set(Math.sign(subX), 0, 0);
        } else {
            this.roleVec.set(0, 0, 0);
        }

        this.role.setPosition(this.rolePos);
    }
    checkPlayer(p: Vec3, r: number) {
        // aabb检测
        let minX = this.roleSize.width * 0.5 + r;
        let minY = this.roleSize.height * 0.5 + r;
        tmpP.set(p).subtract(this.rolePos);
        return Math.abs(tmpP.x) < minX && Math.abs(tmpP.y) < minY;
    }
    //#endregion

    //#region ---触摸
    touchX = 0;
    panelSize = size();
    // 触摸事件
    initTouch() {
        this.tip.active = true;
        this.isStart = false;
        this.touchX = 0;
        this.panelSize.set(this.touchPanel.getComponent(UITransform).contentSize);
        this.touchPanel.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.touchPanel.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.touchPanel.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.touchPanel.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    }
    resetTouch() {
        this.touchX = 0;
        this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.off(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.off(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    }

    onTouchStart(event: EventTouch) {
        this.isStart = true;
        this.tip.active = false;
        this.onTouch(event);
    }
    onTouchMove(event: EventTouch) {
        this.onTouch(event);
    }
    onTouchEnd(event: EventTouch) {
    }

    onTouch(event: EventTouch) {
        event.getUILocation(tmpV2);
        tmpV2.x -= this.panelSize.width * 0.5;
        // 限制范围
        let maxX = (this.boardSize.width - this.roleSize.width) * 0.5;
        if (Math.abs(tmpV2.x) >= maxX) {
            this.touchX = maxX * Math.sign(tmpV2.x);
        } else {
            this.touchX = tmpV2.x;
        }
    }

    //#endregion

    //#region ---小球
    ballSpd = 0;
    // 速度方向-归一化
    ballVec = v3();
    initBallPos = v3(0, -227);
    ballPos = v3();

    initBall() {
        this.ballPos.set(this.initBallPos);
        this.ball.setPosition(this.initBallPos);
        this.ballVec.set(0.5, 1).normalize();

        this.ballSpd = 500 + (StorageSystem.getData().levelAssets.curLv - 1) * 50;
        this.ballSpd = Math.min(this.ballSpd, 1500);
    }

    resetBall() {
        this.ballPos.set(this.initBallPos);
        this.ball.setPosition(this.initBallPos);
    }
    updateBall(dt) {
        // 计算运动轨迹
        tmpP.set(this.ballVec).multiplyScalar(dt * this.ballSpd);
        let isCollX = false;
        let isCollY = false;
        let r = this.ballSize.width * 0.5;
        // 分别计算xy步长
        // 计算X轴
        tmpP1.set(tmpP.x + this.ballPos.x, this.ballPos.y);
        // 计算Y轴
        tmpP2.set(this.ballPos.x, tmpP.y + this.ballPos.y);

        // 1.检测边界
        let maxX = Math.abs(this.boardSize.width * 0.5 - r);
        let maxY = Math.abs(this.boardSize.height * 0.5 - r);
        if (!isCollX) {
            isCollX = Math.abs(tmpP1.x) > maxX;
        }
        if (!isCollY) {
            isCollY = Math.abs(tmpP2.y) > maxY;
        }

        // 2.检测玩家
        if (!isCollX) {
            isCollX = this.checkPlayer(tmpP1, r);
            // 叠加玩家的速度方向
            // this.ballVec.x += 0.5 * this.roleVec.x;
            // this.ballVec.normalize();
        }
        if (!isCollY) {
            isCollY = this.checkPlayer(tmpP2, r);
        }
        // 3.检测grid
        if (!isCollX) {
            isCollX = this.checkGrids(tmpP1, r);
        }
        if (!isCollY) {
            isCollY = this.checkGrids(tmpP2, r);
        }
        // 步长归零,速度反向
        if (isCollX) {
            tmpP1.x = this.ballPos.x;
            this.ballVec.x *= -1;
        }
        if (isCollY) {
            tmpP2.y = this.ballPos.y;
            this.ballVec.y *= -1;
        }
        // 修正Y速度
        if (Math.abs(this.ballVec.y) < 0.2) {
            this.ballVec.y = 0.2 * Math.sign(this.ballVec.y);
        }

        // 4.更新位置
        this.ballPos.set(tmpP1.x, tmpP2.y);
        this.ball.setPosition(this.ballPos);
    }

    //#endregion

    //#region ----击中效果
    effects: { node: Node, p: Vec3, v: Vec3, s: number }[] = [];
    initEffect() {
        this.effectLayer.removeAllChildren();
        this.effects.length = 0;
    }
    resetEffect() {
        this.effects.length = 0;
    }
    updateEffect(dt) {
        for (let i = this.effects.length - 1; i >= 0; i--) {
            let e = this.effects[i];
            tmpV.set(e.v).multiplyScalar(dt);
            e.p.add(tmpV);
            e.node.setPosition(e.p);
            e.s += (0 - e.s) * 0.1;
            e.node.setScale(tmpP.set(e.s, e.s, 1));
            if (e.s <= 0) {
                this.effects.splice(i, 1);
                e.node.removeFromParent();
                e.node.destroy();
            }
        }
    }
    showEffect(p: Vec3) {
        let count = Math.floor(Math.random() * 4 + 4);
        for (let n = 0; n < count; n++) {

            let e = instantiate(this.bubble);
            e.parent = this.effectLayer;
            let pos = v3(p);
            let vec = v3(Math.random() - Math.random(), Math.random() - Math.random()).normalize().multiplyScalar(100);
            e.setPosition(pos);
            this.effects.push({
                node: e,
                p: pos,
                v: vec,
                s: 3
            })
        }
    }

    //#endregion

    //#region ----积分
    @property(Label)
    scoreLabel: Label = null;
    @property(Label)
    targetLabel: Label = null;
    targetScore = 0;
    currScore = 0;

    initScore() {
        this.targetScore = StorageSystem.getData().levelAssets.curLv * 10 + 10;
        this.targetLabel.string = this.targetScore.toString();
        this.currScore = 0;
        this.scoreLabel.string = this.currScore.toString();
    }
    resetScore() {

    }
    addScore(n = 1) {
        this.currScore += n;
        this.scoreLabel.string = this.currScore.toString();
        if (this.currScore >= this.targetScore) {
            this.onGameOver(true);
        }
    }

    //#endregion
}

